/**
 * SBmenu 2.0.0
 * By SBZsoft(c)
 * Writen by: Shlomi Bazak
 * Copyright 2011, Shlomi Bazak
 * 
 * Licensed under the GPL Version 2.
 * Date: Tue Fab 1 2011 15:13:23
 */
(function($) {
	
	var SBMEU_STAGE_CLOSED = 0,
		SBMEU_STAGE_SLIDING_OUT = 1,
		SBMEU_STAGE_SLIDING_DOWN = 2,
		SBMEU_STAGE_OPEN = 3,
		defaults = {
			rtl : false, // true false
			align : null, // left right center // FORCE align on the first sub menu items, of horisontal (not Vertical) menu.
			vertical : false, // vertical, horisontal
			effect : "slide", // fade, slide, show
			activeClass : 'active', // the selected class
			effectTime : 500,
			minLiWidth : 100,
			Zindex : 100
		};

	var sbmenu = function(e, o) {
		this.options = $.extend({}, defaults, o || {});
		if (e.nodeName.toUpperCase() == 'UL')
			this.list = $(e);
		else
			this.list = $(e).find("ul:first");
		this.list.addClass('sbmenu');
		this.list_parent = this.list.parent();
		// Froce the align right on rtl, if align wasn't forced.
		if (this.options.rtl && !this.options.align)
			this.options.align = 'right';
		this.init();
		this.start();
	};

	sbmenu.fn = sbmenu.prototype = {
		version : '2.0.0',
		by : 'SBZsoft'
	};

	sbmenu.fn.extend = $.extend;

	sbmenu.fn.extend({
		last_item : null,
		show_timeout : null,
		hide_timeout : null,
		o : this.options,
		timeout : 500,

		init : function() {
			if (this.options.vertical)	this.list.addClass('vertical');
			var li = this.list.find('.' + this.options.activeClass + ":first"),
				active = true;
			if (li.length) {
				while (li.get(0).tagName.toLowerCase() != 'li'){
					if(li.parent().hasClass('sbmenu')){
						active = false;
						break;
					}
					li = li.parent();
				}
				if(active)
					while(!li.parent().hasClass('sbmenu')){
						li = li.parent().parent();
						li.children('a, span').addClass('activePath');
					}
			}
			this.initUL(this.list, 0);
		},
		
		slideDown: function(el){
			el.stop(true, false);
			el.css('display', 'block');
			el.animate({height: el.get(0).__height}, this.options.effectTime/2, function(){el.css({overflow:'visible', height:''});});
		},

		slideUp: function(el){
			el.stop(true, false);
			el.animate({height: 0}, this.options.effectTime/2, function(){el.css({display:'none'});});
		},
		
		slideIn : function(el) {
			if (!el || !el.length) return;
			var stage = el.get(0).__slideSatge;
			if(stage == SBMEU_STAGE_OPEN) return;
			if(!stage) stage = SBMEU_STAGE_CLOSED;
			el.stop(true, false);
			var ef_time = this.options.effectTime / 2,
				height = el.get(0).__height,
				width = el.get(0).__width,
				d = (el.parent().parent().outerWidth(true) - el.parent().width())/2,
				parentWidth = el.parent().outerWidth(true),
				left = this.options.rtl ? -(width+d) : parentWidth+d,
				stLeft = el.outerWidth(true) < parentWidth && !this.options.rtl ? parentWidth - el.outerWidth(true) : 0,
				stHeight = el.children('li:first').get(0).__height;
			switch (stage) {
			case SBMEU_STAGE_CLOSED :
				el.css({
					height : stHeight,
					display : 'block',
					left : stLeft,
					width : parentWidth-2,
					visibility: 'visible',
					'z-index': -Math.abs(el.css('z-index'))
				});
				el.get(0).__slideSatge = SBMEU_STAGE_SLIDING_OUT;
			case SBMEU_STAGE_SLIDING_OUT:
				el.animate(
					{height:stHeight, left:left, width:width},
					ef_time,
					function() {
						el.css({'z-index': Math.abs(el.css('z-index'))});
						el.parent().css({'z-index': Math.abs(el.css('z-index'))+1});
						el.get(0).__slideSatge = SBMEU_STAGE_SLIDING_DOWN;
					}
				);
			case SBMEU_STAGE_SLIDING_DOWN:
				el.animate(
					{height:height},
					ef_time, 
					function() {
						el.css({overflow : 'visible'});
						el.get(0).__slideSatge = SBMEU_STAGE_OPEN;
					}
				);
			} 
		},

		slideOut : function(el) {
			if (!el || !el.length) return;
			el.stop(true, false);
			var stage = el.get(0).__slideSatge,
				ef_time = this.options.effectTime / 2,
				left = 2,
				maxWidth =  el.parent().outerWidth(true) - 2,
				width = el.outerWidth(true) > el.parent().outerWidth(true) ? el.parent().outerWidth(true) - 5 : el.outerWidth(true) -5,
				height =  el.children('li:first').outerHeight(true);
			
			switch (stage) {
			case SBMEU_STAGE_OPEN:
				el.get(0).__slideSatge = SBMEU_STAGE_SLIDING_DOWN;
			case SBMEU_STAGE_SLIDING_DOWN:
				el.animate(
					{height:height}, 
					ef_time,
					function(){
						el.get(0).__slideSatge = SBMEU_STAGE_SLIDING_OUT;
					}
				);
			case SBMEU_STAGE_SLIDING_OUT:
				el.queue(function(){
					el.css({'z-index':-Math.abs(el.css('z-index'))});
					el.parent().css({'z-index':Math.abs(el.css('z-index'))-1});
					el.dequeue();
				});
				el.animate(
					{left:left, width:width, height:height}, 
					ef_time, 
					function(){
						el.css({'display': 'none', visibility: 'hidden'});
						el.get(0).__slideSatge = SBMEU_STAGE_CLOSED;
					}
				);
			}
		},

		show_item : function(item) {
			if (!item || !item.length)
				return;
			clearTimeout(item.get(0).timeOut);
			// the load hack.
			item.css({visibility : 'visible'});
			switch (this.options.effect) {
			case "fade":
				item.fadeIn(this.options.effectTime);
				break;
			case "slide":
				if (!this.options.vertical && item.parent().parent().hasClass('sbmenu'))	this.slideDown( item ) ;
				else	this.slideIn(item);
				break;
			default:
				item.show(this.options.effectTime);
			}
		},

		hide_item : function(item) {
			if (!item || !item.length)
				return;
			var self = this;
			item[0].timeOut = setTimeout(function() {
				switch (self.options.effect) {
				case "fade":
					item.fadeOut(self.options.effectTime);
					break;
				case "slide":
					if (!self.options.vertical && item.parent().parent().hasClass('sbmenu'))	self.slideUp( item ) ;
					else	self.slideOut(item);
					break;
				default:
					item.hide(self.options.effectTime);
				}
			}, this.timeout);
		},

		setDims : function(el, level) {
			var dims = findMaxWidthHeight(el);
			var width = dims[0], height = dims[1];
			if (width < this.options.minLiWidth)
				width = this.options.minLiWidth;
			if(level == 1 && !this.options.vertical && width < el.parent().outerWidth(true))
				width =  el.parent().outerWidth();
			if (level > 0 || this.options.vertical) {
				el.children('li').css({width: width});
				el.css({
					width : width,
					height : height
				});
			}
			if (level > 0)
				el.children('li').children('ul').css('left', width + 'px');
			el.get(0).__width = width;
		},

		handleFirstLevel : function(ul) {
			var left = 0;
			switch (this.options.align) {
			case 'right':
				left = ul.parent().outerWidth(true) - ul.outerWidth(true);
				break;
			case 'center':
				left = ul.parent().outerWidth(true) / 2 - ul.outerWidth(true) / 2;
				break;
			}
			var top = ul.parent().outerHeight(true);
			ul.css({
				left : left,
				top : top
			});
		},

		setUlPosition : function(ul) {
			ul.css({
				left : -ul.outerWidth(true)
			});
		},

		initUL : function(ul, level) {
			this.setDims(ul, level);
			ul.get(0).__height = ul.height();
			if (!this.options.vertical && level == 1)
				this.handleFirstLevel(ul);
			else if (level > 1 && this.options.rtl)
				this.setUlPosition(ul);
			var fch = ul.children('li:first');
			fch.get(0).__height = fch.outerHeight(true);
			if(level == 1 && !this.options.vertical)
				ul.css({height: 0});
			ul.css({'z-index': this.options.Zindex+level}).children().css({'z-index': this.options.Zindex+level});
			// Recursive call to handle all elements.
			var self = this;
			ul.children('li').each(function(a, i) {
				if ($(this).children('ul').length)
					self.initUL($(this).children('ul'), level + 1);
			});
		},

		start : function() {
			var self = this;
			this.list.find('ul').css({
				display : "none"
			}); // Opera Fix
			this.list.find('li').hover(function() {
				if ($(this).children('ul').length) {
					self.show_item($(this).children('ul'));
				}
			}, function() {
				if ($(this).children('ul').length)
					self.hide_item($(this).children('ul'));
			});
		}
	});

	/**
	 * Private function to find the max width within the UL element. and the
	 * elements height;
	 */
	function findMaxWidthHeight(ul) {
		var width = 0;
		var height = 0;
		ul.children('li').each(
				function() {
					width = $(this).outerWidth(true) > width ? $(this).outerWidth(true) : width;
					height += $(this).outerHeight(true);
				});
		return [ width, height ];
	}

	$.fn.sbmenu = function(o) {
		return this.each(function() {
			$this = $(this);
			if ($this.data('sbmenu'))
				return;
			$this.data('sbmenu', new sbmenu(this, o));
		});
	};
})(jQuery);